/*
 *  cda/src/compress.c
 *
 *  (C) 2011 Harry Wei
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>

#include "../include/cda.h"

/*
 * compress_file: compress a file.
 * @file_name: the file's name.
 * @compress_file: compressed file name.
 * @effect_fre: the effective characters and their frequencies.
 * @hc: the effective characters' huffman code.
 * @counter: the effective characters' amounts.
 */

int 
compress_file(char *file_name, char *compress_file,
		struct ch_fre *effect_fre, struct huffcode *hc, int counter)
{
	int i = 0;
	int code_counter = 0;
	int fd;
	int fd_read;
	char ret;
	char c = '\0';
	char label[] = "cda";
	char ch;
	char case_value = 1;
	struct byte wr_cf;
	
	for (i = 1; i < counter + 1; i++) {
		printf("IM@: %d\n", hc[i].ch);
	}
	if ((fd = creat(compress_file, 0644)) < 0) {			/* Begin write file name */
		fprintf(stderr, "Creat File Error!\n");
		return 1;
	}
	if (sizeof(label) != write(fd, label, sizeof(label))) {		/* Write our label */
		fprintf(stderr, "1 Write Error!\n");
		return 1;
	}								/* Write over */
	if ((fd_read = open(file_name, O_RDONLY)) < 0) {		/* Open the original file */
		fprintf(stderr, "Creat File Error!\n");
		return 1;
	}								/* Open Over */
	i = 0;
	while (file_name[i]) {						/* Write file name */
		if (sizeof(char) != write(fd, 
				&file_name[i], sizeof(char))) {
			fprintf(stderr, "1 Write Error!\n");
			return 1;
		}
		printf("file name: %c\n", file_name[i]);
		i = i + 1;
	}
	if (sizeof(char) != write(fd, &c, sizeof(char))) {
		fprintf(stderr, "2 Write Error!\n");
		return 1;
	} 								/* Write file name over */
	if (sizeof(int) != write(fd, &counter, sizeof(int))) {		/* Write Counter */
		fprintf(stderr, "3 Write Error!\n");
		return 1;
	}								/* Write Over */
	for (i = 1; i < counter + 1; i++) {				/* Write huff fre */
		if (sizeof(struct ch_fre) != write(fd, 
				&effect_fre[i], sizeof(struct ch_fre))) {
			fprintf(stderr, "5 Write Error!\n");
			return 1;
		}	 							
	}								/* Write Over */
	while ((ret = read(fd_read, &ch, sizeof(char)))) {		/* Write Huffcode */
		if (ret != sizeof(char)) {
			fprintf(stderr, "Read Error!\n");
			return 1;
		}
		for (i = 1; i < counter + 1; i++) {
			if (ch == hc[i].ch) {
				for (code_counter = hc[i].begin; 
					code_counter < CHAR_USE; code_counter++) {
					switch (case_value) {
						case 1:
							wr_cf.bit1 = hc[i].code[code_counter];
							case_value = case_value + 1;
							break;
						case 2:
							wr_cf.bit2 = hc[i].code[code_counter];
							case_value = case_value + 1;
							break;
						case 3:
							wr_cf.bit3 = hc[i].code[code_counter];
							case_value = case_value + 1;
							break;
						case 4:
							wr_cf.bit4 = hc[i].code[code_counter];
							case_value = case_value + 1;
							break;
						case 5:
							wr_cf.bit5 = hc[i].code[code_counter];
							case_value = case_value + 1;
							break;
						case 6:
							wr_cf.bit6 = hc[i].code[code_counter];
							case_value = case_value + 1;
							break;
						case 7:
							wr_cf.bit7 = hc[i].code[code_counter];
							case_value = case_value + 1;
							break;
						case 8:
							wr_cf.bit8 = hc[i].code[code_counter];
							if (sizeof(struct byte) != write(fd, &wr_cf, 
										sizeof(struct byte))) {
								fprintf(stderr, "6 Write Error!\n");
								return 1;
							}
							case_value = 1;
							break;
					}
				}
			}
		}
	}									
	/*
	 *  Here: If up operations remain some bits, which can not
	 *  make up with 8 bits. So we can just do following for it.
	 */
	if (sizeof(struct byte) != write(fd, &wr_cf, sizeof(struct byte))) {
		fprintf(stderr, "6 Write Error!\n");
		return 1;
	}									/* Write Over */
	if (close(fd_read)) {
		fprintf(stderr, "Close Error!\n");
		return 1;
	}
	if (close(fd)) {
		fprintf(stderr, "Close Error!\n");
		return 1;
	}
	return 0;
}
